/**
 * 
 */
package com.cuc.platform.core.componet.security;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.config.Ini;
import org.apache.shiro.config.Ini.Section;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * Shiro的拦截过滤链
 * 
 * 拦截规则：按从前至后的顺序拦截，所以粒度细的url要在前面
 * 			最后设/** = authc 表示未做设置的url都是需要认证的
 * 
 *     示例：	/login.jsp* = anon 匿名用户
				/security/** = perms[admin, 其他权限。。] 权限
				/baseInfo/** = perms[user] 用户角色
				/** = authc
 
 */
public class ShiroFilterChainDefinitions implements FactoryBean<Ini.Section>{

    /**
     * 通过filterChainDefinitions对默认的url过滤定义
     * 
     * @param filterChainDefinitions 默认的url过滤定义
     */
    public void setFilterChainDefinitions(String filterChainDefinitions) {
        this.filterChainDefinitions = filterChainDefinitions;
    }

    public Class<?> getObjectType() {
        return this.getClass();
    }

    public boolean isSingleton() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.springframework.beans.factory.FactoryBean#getObject()
     */
    public Section getObject() throws BeansException {

        //获取所有Resource对应的权限
        List<ShiroResource> list = this.getAuthRescs();

        Ini ini = new Ini();
        
        //加载默认的url
        ini.load(filterChainDefinitions);
        Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
      
        /* 循环Resource的url,逐个添加到section中。section就是filterChainDefinitionMap,
                      里面的键就是链接URL,值就是存在什么条件(当前统一为权限)才能访问该链接
        */
        for (Iterator<ShiroResource> it = list.iterator(); it.hasNext();) {
        	ShiroResource srObj = it.next();
        	String res = srObj.getResource();//url
        	String auth = srObj.getAuthority();//perm
        	
            if(StringUtils.isNotEmpty(res) && StringUtils.isNotEmpty(auth)) {
            	if(section.containsKey(res)) {
            		//设置section的url对应多个权限的情况。
            		//当一个url对应多个auth时，登录用户必须具备所有权限才可以访问
            		String prePerm = section.get(res);
            		String permSplit = "perms[";
            		String perms = StringUtils.replace(prePerm, permSplit, permSplit + auth + ",");
            		section.put(res, perms);
            	} else {
            		section.put(res,  MessageFormat.format(PREMISSION_STRING,auth));
            	}
            }
        }

        //在过滤链最后加上/**，以可以让认证成功的用户访问未特别授权的资源
        section.put("/**", "authc");
        return section;
    }

	/**
	 * 获取权限-资源关联数据
	 * 	
	 * 注：url 不建议一个url对应多个auth的情况，因权限的粒度已经是最小粒度。
	 *     
	 *     即一个auth可以配置给多个url，但一个url不建议同时配置多个auth
	 * @return  List<ShiroResource>
	 */
    private List<ShiroResource> getAuthRescs(){
    	List<ShiroResource> list = new ArrayList<ShiroResource>();

   	
		final String resourceQuery = 
				"SELECT re.res_string as resource, au.name as authority " +
				"FROM ss_auth au " +
				"JOIN ss_auth_resc ar ON au.id = ar.auth_id " +
				"JOIN ss_resc re ON re.id = ar.resc_id " +
				"ORDER BY re.priority";
		
		list = jdbcTemplate.query(resourceQuery, new BeanPropertyRowMapper<ShiroResource>(ShiroResource.class));
		
		return list;
    }
    

    private String filterChainDefinitions;

    /**
     * 默认premission字符串
     */
    private static final String PREMISSION_STRING="perms[{0}]";
    //private static final String ROLE_STRING="roles[{0}]";
    
	@Resource
	private JdbcTemplate jdbcTemplate;//为减少耦合，直接取数据
}
